perm filename MXMPLS.PUB[HAL,HE] blob
sn#133580 filedate 1974-12-04 generic text, type C, neo UTF8
COMMENT ⊗ VALID 00008 PAGES
C REC PAGE DESCRIPTION
C00001 00001
C00002 00002 .NEWSEC PROGRAMMING EXAMPLES,BOLTING A BRACKET
C00007 00003 .ex1: NEWSSS EXAMPLE ONE
C00016 00004 .NEWSSS EXAMPLE TWO
C00026 00005 .NEWSSS EXAMPLE THREE
C00040 00006
C00044 00007 .NEWSS EXAMPLES OF COORDINATED ACTION, COORDINATED ACTION
C00052 00008 .NEWSS A α`VERY HIGH LEVELα' EXAMPLE
C00058 ENDMK
C⊗;
.NEWSEC PROGRAMMING EXAMPLES,BOLTING A BRACKET
.NEWSS BOLTING A BRACKET ONTO A BEAM, BOLTING A BRACKET
.FILL
This is intended to be a series of progressively more complex
examples which demonstrate some of the features in AL, including
affixment, control structures, macros, and library routines.
The first set of
the examples have essentially the same goal: bolt a bracket to a beam.
Each example takes into account more possibilities or contains a
different way of expressing the same thing.
The initial affixment structure is:
.NOFILL
STATION
YELLOW
BLUE
BRACKET
BRACKET_HOLE
BRACKET_GRASP
BOLT
BEAM
BEAM_HOLE
The final affixment structure is:
STATION
YELLOW
BLUE
BEAM
BEAM_HOLE
BRACKET
BRACKET_HOLE
BRACKET_GRASP
BOLT
.FILL
The initial structure can be created by the following declarations
and assignments.
See {NEWFIG Initial World,FULL}.
.NOFILL
FRAME beam, beam_hole;
FRAME bracket, bracket_hole, bracket_grasp;
FRAME bolt;
beam α← FRAME(ROT(Z, 90*DEG), VECTOR(30, 24.2, 0));
.COMT 4
α{Beam is not affixed to anything initially. Thus its
default DEPROACH is the station's DEPROACH which is:
TRANS(NILROT, 10*CM*Z)α}
.END
beam_hole α← beam * FRAME(ROT(X, -90*DEG), VECTOR(5.1, 0, 15));
.COMT 4
α{FRAME(ROT(X, -90*DEG), VECTOR(5.1, 0, 15))
is the relative transform from
beam to the beam_hole. Another way of looking at this is that
within the beam's frame of reference, the beam_hole is at
FRAME(ROT(X, -90*DEG), VECTOR(5.1, 0, 15))
The premultiplication by beam transforms
this relative location out to the corresponding position (in station
coordinates) with respect to the current location of beam.α}
.END
AFFIX beam_hole TO beam;
ASSERT FORM(DEPROACH, beam_hole, TRANS(NILROT, VECTOR(0, 0, -3));
.COMT 4
α{this sets up a DEPROACH of -3 centimeters in the Z direction
of the beam_hole's coordinate system.α}
.END
bracket α← FRAME(ROT(Z,90*DEG), VECTOR(20, 40, 0));
bracket_hole α← bracket * FRAME(ROT(X, 180*DEG), VECTOR(5.1, 2, 0));
AFFIX bracket_hole TO bracket;
bracket_grasp α← bracket * FRAME(ROT(X, 180*DEG), VECTOR(0, 1.5, 5));
AFFIX bracket_grasp TO bracket RIGIDLY;
.COMT 4
α{Notice that changing bracket_grasp will automatically change
bracket, which in turn will automatically change bracket_hole. This
is very handy if the position of the whole `object' is being
updated by one grasping position (ie. bracket_grasp.α}
.END
bolt α← FRAME(ROT(Z,90*DEG)*ROT(X,180*DEG), VECTOR(30, 60, 5));
.COMT 4
α{The bolt is assumed to be sticking out of a dispenser.α}
.END
.ex1: NEWSSS EXAMPLE ONE
The task involves the following steps:
.BEGIN INDENT 8,12; FILL;PREFACE 0;
(1) Pick up the bracket with the YELLOW arm and position
it next to the beam so that the holes line up.
(2) Pick up the bolt with the BLUE arm and insert
it in the hole (in this example it is not screwed
in; a later example will use a socket driver
to tighten the bolt).
(3) Return both arms to park.
.END
.FILL
The bracket is assumed to be 1 cm thick , and the bolt 4 cm long.
The following program is a straightforward way to express the
motions and feedback necessary to carry out the task. Everything is
assumed to be in the right place and every motion is assumed to
accomplish its desired effect. For example, this program assumes
that the arm is accurate enough to align the bracket_hole with the
beam_hole and to insert the bolt without hitting the side or binding.
Later examples will take this type of error into account.
.NOFILL
DEFINE OZ = "72.007789*DYNES";
.comt 4
α{This macro defines a unit of force OZ equal to 1/16 poundalα}
.END
OPERATE YFINGERS WITH OPENING=3*CM;
MOVE YELLOW TO bracket_grasp;
.comt 4
α{Since bracket_grasp does not have a DEPROACH explicitly
associated with it, the compiler checks to see if it is
affixed to anything. It is: bracket. But bracket does not
have a DEPROACH associated with it either. Is it affixed
to anything? No. Therefore, by default the compiler uses the STATION's
DEPROACH (ie. TRANS(NILROT,10*CM*Z)) as the approach for
bracket_grasp.α}
.END
CENTER YELLOW;
.COMT 4
α{This closes the fingers until they grab something.α}
.END
bracket_grasp α← YELLOW;
.COMT 4
α{Since bracket_grasp is RIGIDLY affixed to bracket, this
statement updates bracket and hence anything affixed to
bracket (eg. bracket_hole). In effect, the assumption being
made is that the position of the whole `object' (ie. the bracket)
can be updated by locating bracket_grasp. In the usage above the
arm moves to the planning position for bracket_grasp and then
centers itself about the object between its fingers. Notice that
the final position of the arm may very well not be bracket_grasp
(because of the accommodation during the centering). Therefore,
the bracket might not be where it was planned to be. This discrepancy
between the planned world and the `actual' world has to be
reconciled. The simplest assumption (and the assumption being used here)
is that the only difference between the planned location and the
actual is that the `whole' bracket has been moved along the line between
the fingers so that bracket_grasp is where the arm found it. More
complicated updating could be done by visually locating the bracket
and reseting bracket or by feeling the bracket two or three times,
combining the resulting locations into a new estimate of bracket's
location, and reseting bracket. Notice that if the CENTER moved the arm
away from the planned location and no updating were done, the AFFIX
statement which follows would affix the bracket to
the YELLOW arm in such a way that the bracket was assumed to be at
its planning position (which would be wrong). The subsequent move
to the beam_hole would also be off by the same amount.α}
.END
AFFIX bracket TO YELLOW;
MOVE bracket_hole TO beam_hole;
.COMT 4
α{Notice that the bracket approaches the beam from the side
(not from above) because of the DEPROACH set up for beam_hole.
In this example the bracket is assumed to go right next
to the beam.
This MOVE is a move for the YELLOW arm (because the bracket
is AFFIXed to it). From the definition of affixment this
means that anything affixed to the YELLOW arm is automatically
moved. Thus, bracket, bracket_hole, and bracket_grasp are all
updated. The fact that the move was specified by mentioning
bracket_hole (and not YELLOW) does not change the automatic
updating within the graph structure. Notice, in particular,
that this is quite different from:
.BEGIN NOFILL
AFFIX bracket TO YELLOW
bracket_hole α← beam_hole
.END
which would change the value of bracket_hole and the relative
position between bracket and bracket_hole, but leave YELLOW and bracket
unchanged.α}
.END
OPERATE BFINGERS WITH OPENING=3*CM;
MOVE BLUE TO bolt;
.COMT 4
α{The station's APPROACH is used since the bolt is not affixed
to anything.α}
.END
CENTER BLUE;
bolt α← BLUE;
.COMT 4
α{This insures that the latest value of bolt is used in the AFFIX
command below.α}
.END
AFFIX bolt TO BLUE;
MOVE bolt TO beam_hole + VECTOR(0, 0, -5.3) WRT beam_hole;
.COMT 4
α{This should position the bolt .3 centimeters from the bracket.
That is, the YELLOW arm is now holding the bracket right next to the
beam (with the bracket_hole aligned with the beam_hole) and the BLUE
arm is holding the bolt 5.3 centimeters away from the bracket_hole
(which is equivalent to beam_hole). But remember that the
bracket is 1 cm thick and the bolt is 4 cm long;
thus the tip of the bolt is 1.3 cm from the beam_hole
(or .3 off of the bracket).α}
.END
MOVE BLUE TO ⊗ + VECTOR(0, 0, 5) WRT beam_hole;
WITH FORCE = 0 ALONG X,Y OF BLUE
ON FORCE(Z WRT BLUE) > 60*OZ DO STOP BLUE;
.COMT 4
α{The arm stops when the bolt hits the bottom of the hole.
No DEPARTURE or APPROACH is used because the destination
involves the "⊗" construct.α}
.END
OPERATE YFINGERS WITH OPENING = 3*CM;
UNFIX bracket FROM YELLOW;
AFFIX bracket TO beam;
MOVE YELLOW TO YPARK;
OPERATE BFINGERS WITH OPENING = 3*CM;
UNFIX bolt FROM BLUE;
AFFIX bolt TO beam;
MOVE BLUE TO BPARK;
WRITE("Finished");
END;
.NEWSSS EXAMPLE TWO
.FILL
This version adds a number of checks (and some automatic recoveries)
for possible run-time errors such as not inserting the bolt. It also
utilizes the COBEGIN - COEND capability to describe simultaneous
(unordered, independent) actions. Thus, the Yellow arm can be
picking up the bracket and positioning it near the beam while the
Blue arm is picking up the bolt. Collision avoidance is currently
the responsibility of the user.
.NOFILL
DEFINE OZ="((72.007789*GM*CM)/(SEC*SEC))";
positioning: COBEGIN
ypickup: BEGIN α{%4pick up bracket by YELLOW%*α}
OPERATE YFINGERS WITH OPENING=3*CM;
MOVE YELLOW TO bracket_grasp;
CENTER YELLOW
ON OPENING = 0*CM DO
missed: BEGIN α{%4missed bracket%*α}
STOP YELLOW;
SCALAR flag;
OPERATE YFINGERS WITH OPENING=3*CM;
MOVE YELLOW
TO bracket_grasp * DEPROACH(bracket_grasp) DIRECTLY;
.COMT 14
α{This should safely move the arm away so the
operator can easily insert the missing bracket. It moves
the arm back out to the bracket_grasp's approach point
at runtime.α}
.END
WRITE("The bracket is missing. Position it and type `1' to try again");
READ(flag);
IF flag ≠ 1 THEN ABORT ("Giving up; you didn't type `1'");
.COMT 14
α{The ABORT stops everything, saves the world, and forces
the operator to deal with the problem at supervisor level,
possibly investigating the saved information, reinitializing
the world to some previous state and restarting.α}
.END
MOVE YELLOW TO bracket_grasp DIRECTLY;
.COMT 14
α{this results in a simple move without a DEPARTURE
or an APPROACH.α}
.END
CENTER YELLOW
ON OPENING=0*CM DO ABORT("I tried twice; I give up!");
END missed;
YELLOW α←α← bracket_grasp;
.COMT 8
α{This tells the compiler that the yellow arm can be
assumed to be at bracket_grasp no matter how control got here,
eg. possibly moving away and retrying the grasp.
The "α←α←"
specifies that the planning value of bracket_grasp
should be used to update the compiler's view of where the YELLOW
is.α}
.END
bracket_grasp α← YELLOW;
.COMT 8
α{This generates code to be run at run-time which updates
the frame bracket_grasp (which in turn updates bracket and bracket_hole).
The result is that the following AFFIX uses the best run-time
value of the bracket's position.α}
.END
AFFIX bracket TO YELLOW;
MOVE bracket_hole TO beam_hole + VECTOR(0, 0, 1.3) WRT beam_hole;
.COMT 8
α{This uses the STATION's DEPARTURE (since the bracket is not
affixed to anything) and the beam_hole's approach
(since it is the only frame mentioned in the destination).
This move should position the bracket just off of
the beam. The next motion pushes it up against the beam.α}
.END
MOVE YELLOW TO ⊗ + VECTOR(0, 0, .5) WRT beam_hole
ON FORCE(Z WRT beam_hole) > 50*OZ DO STOP YELLOW
ON ARRIVAL DO ABORT ("I seem to have gone too far");
.COMT 8
α{Give up if the expected force is not felt.
"ARRIVAL" means that the arm reached its destination
without being stopped by any of the
condition monitors. In this case this means that the arm
did not reach the expected force, which means that
something went wrong.
The STOP YELLOW disables all condition monitors for the yellow
arm.α}
.END
END ypickup;
bpickup: BEGIN α{pick up bolt by BLUEα}
.COMT 8
α{Meanwhile the BLUE arm can be picking up the bolt.α}
.END
OPERATE BFINGERS WITH OPENING=3*CM;
MOVE BLUE TO bolt;
CENTER BLUE;
.COMT 8
α{Assume everything is OK.α}
.END
bolt α← BLUE;
AFFIX bolt TO STATION;
END bpickup
COEND positioning;
.COMT 0
α{The bracket should be positioned next to the beam and the BLUE arm
should be holding the bolt.α}
.END
MOVE bolt TO beam_hole + VECTOR(0, 0, -5.3) WRT beam_hole
WITH DEPROACH(beam_hole);
.COMT 4
α{This should position the bolt .3 centimeter off of the bracket.α}
.END
.COMT 0
α{Now begin a search just in case the bolt doesn't immediately go in the
hole: make .2 cm steps around in a spiral; if the bolt does not
go in within nine tries, abort the program.α}
.END
FRAME set; SCALAR n;
.COMT 4
α{n is the number of attempts.α}
.END
n α← 0;
set α← BLUE;
.COMT 4
α{Save initial arm position.α}
.END
SEARCH BLUE
INCREMENT .2*CM
ACROSS PLANE(NILVEC,Z WRT beam_hole)
REPEATING
inserting: BEGIN
MOVE BLUE TO ⊗ + VECTOR(0, 0, 1.6) WRT beam_hole
ON FORCE(Z WRT beam_hole) > 60*OZ DO
missed: BEGIN
STOP BLUE;
n α← n + 1;
IF n > 9 THEN ABORT ("Giving up the search");
MOVE BLUE TO set
END missed
ON ARRIVAL DO TERMINATE;
.COMT 14
α{This means that if the MOVE succeeds in reaching
its goal, stop the search. TERMINATE is a key word
within SEARCHs.α}
.END
END inserting;
BLUE α←α← beam_hole + VECTOR(0, 0, 3.7) WRT beam_hole;
.COMT 4
α{Expect to have the bolt (which is 4 cm long) .3 cm into the hole.α}
.END
MOVE BLUE TO ⊗ * FRAME(ROT(Z, 90*DEG), VECTOR(0, 0, 4))
WITH FORCE = 0 ALONG X,Y OF BLUE
ON FORCE(Z WRT BLUE) > 60*OZ DO STOP BLUE;
.COMT 8
α{This moves the arm 4 cm straight ahead and
twists it 90 degrees about its Z axis (ie. straight
ahead). Thus it moves ahead and twists.α}
.END
disengage: COBEGIN
foryellow: BEGIN
OPERATE YFINGERS WITH OPENING = 3*CM;
UNFIX bracket FROM YELLOW;
AFFIX bracket TO beam;
MOVE YELLOW TO YPARK
END foryellow;
forblue: BEGIN
OPERATE BFINGERS WITH OPENING = 3*CM;
UNFIX bolt FROM BLUE;
AFFIX bolt TO beam;
MOVE BLUE TO BPARK
END forblue
COEND disengage;
WRITE("Finished");
END;
.NEWSSS EXAMPLE THREE
.FILL
This example employs a text macro to simplify definitions, a macro
to shorten the code for searching, and a library routine to grasp
things. The library routine is supposed to cover a number of
possibilities and provide for a number of parameters. Since library
routines can be called with a subset of their parameters filled in,
the routine's flexibility is not oppressive for those users who just
want to do something simple.
.NOFILL
DEFINE define_wrt(new_frame, main_frame, position) =
"new_frame α← main_frame * position;
AFFIX new_frame TO main_frame";
A typical call might be:
define_wrt(bracket_hole, bracket, FRAME(ROT(X, 180*DEG), VECTOR(5.1, 2, 0));
which would expand into:
bracket_hole α← bracket * FRAME(ROT(X, 180*DEG), VECTOR(5.1, 2, 0));
AFFIX bracket_hole TO bracket;
.FILL
The following macro produces a string of tokens which imply a compile-time
check on the value of the conditional expanded by the parameter
RIGID. If RIGID evaluates to TRUE then the token sequence which rigidly
affixes the new frame to the main frame is used.
.NOFILL
DEFINE DEFINE_WRT(new_frame, main_frame, position, rigid) =
"new_frame α← main_frame * position;
PLAN IF rigid
THEN AFFIX new_frame TO main_frame RIGIDLY
ELSE AFFIX new_frame TO main_frame";
Another, more complicated macro to facilitate a normal search:
DEFINE normal_search(the_arm, increm, dist_fwd, stopping_force, num_tries) =
"BEGIN α{%4This BEGIN is part of the macro code.%*α}
FRAME set; SCALAR n;
.COMT 10
α{n is the number of attempts.α}
.END
n α← 0;
set α← the_arm;
.COMT 10
α{Save initial arm position.α}
.END
SEARCH the_arm
INCREMENT increm
ACROSS PLANE(NILVEC, Z WRT the_arm)
REPEATING
insertion: BEGIN
MOVE the_arm TO ⊗ + (dist_fwd*Z) WRT the_arm
ON FORCE(Z WRT the_arm) > stopping_force DO
missed: BEGIN
STOP the_arm;
n α← n + 1;
IF n > num_tries THEN ABORT(""Giving up"");
MOVE the_arm TO set;
END missed
ON ARRIVAL DO TERMINATE
END insertion;
ASSERT the_arm = α#(set) + VECTOR(0, 0, dist_fwd);
.COMT 10
α{This changes the compiler's view to believe that the arm
succeeds on the first attempt, and hence the planning
value for the arm will be the distance forward plus set.α}
.END
END";
.FILL
Notice that a pair of adjacent quotes inside of a macro definition
(delimited by quotes) denotes a single quote.
A typical call would be:
.NOFILL
normal_search(YELLOW, .2*CM, 1.6*CM, 60*OZ, 9);
The above macro could easily be made into a library routine as follows:
ROUTINE normal_search(FRAME the_arm; DISTANCE SCALAR increm, dist_fwd;
FORCE SCALAR stopping_force;
SCALAR num_tries(DEFAULT 9));
BEGIN
:
END;
The corresponding call:
normal_search(YELLOW, .2*CM, 1.6*CM, 60*OZ, 9);
.FILL
The "9" is a default value if no value is specified in the call. Thus, by
naming the parameters the same call can be made by:
.NOFILL
normal_search(the_arm=YELLOW, dist_fwd=1.6*CM,
stopping_force=60*OZ, increm=.2*CM);
Notice that the order is not important if the parameters are named.
.FILL
The following routine is a library routine to grasp things. Basically it
does the following:
.BEGIN FILL; INDENT 8,12
(1) Optionally open to an opening_before_departure.
(2) Depart via a departure (if there is one; a special_departure
can be specified).
(3) Start opening the fingers to the opening_for_approach at the
departure point (if special_departure is specified, use it.
Otherwise, use the standard DEPROACH value.).
(4) Approach the grasping_point via the APPROACH (if a
special_approach is specified, use it).
(5) Center on the object. (If the fingers close so that the opening is
less than (thickness#-#.10) call the operator and give him one
chance to re-position the object and try again.)
(6) Upon successfully centering on the grasp_point, update the
object's position by assigning the grasp_point the current hand
location (this, of course, assumes that either the grasp_point
and the object are the same frame or that the grasp_point is
RIGIDLY affixed to the object).
.END
.NOFILL
Notice that this routine can be used by either arm.
ROUTINE grasp(TRANS special_departure, special_approach;
FRAME ATOM the_arm (DEFAULT YELLOW);
FRAME object, grasp_point, thing_object_affixed_to;
DISTANCE SCALAR opening_before_departure,
opening_for_approach(DEFAULT 15*CM),
thickness(DEFAULT .3*CM));
.COMT 8
α{Special_departure is a trans for the relative
position of departure.
Special_approach is a trans for the relative
position of the approach.
Thing_object_affixed_to is the name of the frame that the object
is affixed to (if there is one) before the grasp
routine is called. It is used to specify from what the
object should be unfixed upon being grasped.
Thickness is defaulted to .3*CM so that the condition monitor
ON#OPENING#<#(thickness#-#.2*CM)#DO ... will do a
reasonable thing.α}
.END
grasping: BEGIN
ATOM the_fingers;
CLAUSE t, u;
PLAN IF α#(the_arm) = BLUE
THEN the_fingers α←α← BFINGERS
ELSE the_fingers α←α← YFINGERS;
.COMT 8
α{This sets up the atom the_fingers
to expand into the correct device name for the
OPERATE statements (depending upon the choice of arm).α}
.END
PLAN IF SPECIFIED(opening_before_departure) THEN
OPERATE α#(the_fingers) WITH OPENING=opening_before_departure;
.COMT 8
α{The next statement sets up a clause,
u, which contains the phrase "WITH#APPROACH#=#<the special>"
or NILDEPROACH depending upon whether or not a special approach
has been specified. This constructed phrase is used in two
or three places below to insure that the desired approach is
being used.α}
.END
PLAN IF SPECIFIED(special_approach)
THEN u α←α← CLAUSE(WITH APPROACH = special_approach )
ELSE u α←α← NILCLAUSE;
PLAN IF SPECIFIED(special_departure)
THEN MOVE α#(the_arm) TO grasp_point
WITH DEPARTURE=NILDEPROACH
VIA α#(the_arm) * special_departure THEN
BEGIN
OPERATE α#(the_fingers)
WITH OPENING=opening_for_approach
END
α#(u)
ELSE MOVE α#(the_arm) TO grasp_point
WITH DEPARTURE=NILDEPROACH
VIA α#(the_arm) * DEPROACH(grasp_point) THEN
BEGIN
OPERATE α#(the_fingers)
WITH OPENING=opening_for_approach
END
α#(u);
CENTER α#(the_arm)
ON OPENING < (THICKNESS-.2*CM) DO
missed: BEGIN
STOP α#(the_arm);
SCALAR flag;
OPERATE the_fingers WITH OPENING=opening_for_approach;
PLAN IF SPECIFIED(special_approach)
THEN BEGIN α{%4move to special approach point%*α}
MOVE α#(the_arm) TO α#(the_arm) * special_approach
DIRECTLY
END
ELSE BEGIN α{%4use the normal approach%*α}
MOVE α#(the_arm)
TO α#(the_arm)* DEPROACH(grasp_point)
DIRECTLY;
END
WRITE("Grasp failed; Type a `1' to retry");
READ(flag);
.COMT 12
α{This is simply "wait for proceed".α}
.END
IF flag ≠ 1 THEN ABORT;
MOVE α#(the_arm) TO grasp_point DIRECTLY;
CENTER α#(the_arm)
ON OPENING < (THICKNESS-.2*CM) DO ABORT ("Closed on air");
END missed;
grasp_point α← α#(the_arm);
PLAN IF SPECIFIED(thing_object_affixed_to) THEN
UNFIX object FROM thing_object_affixed_to;
AFFIX object TO α#(the_arm);
END grasping;
The following is a typical call on such a routine:
grasp(the_arm=YELLOW, object=bracket,
grasp_point=bracket_grasp,
special_approach=FRAME(ROT(Z,90*DEG),VECTOR(0,0,-3)),
opening_for_approach=3*CM);
which expands into:
MOVE YELLOW TO bracket_grasp
WITH DEPARTURE=NILDEPROACH
VIA YELLOW * FRAME(NILROT,10*Z) THEN
BEGIN
OPERATE YFINGERS WITH OPENING=3*CM
END
WITH APPROACH = FRAME(ROT(Z,90*DEG), VECTOR(0,0,-3));
CENTER YELLOW
ON OPENING < .2*CM DO
missed: BEGIN
STOP YELLOW;
SCALAR flag;
OPERATE YFINGERS WITH OPENING=3*CM;
MOVE YELLOW
TO YELLOW*FRAME(ROT(Z,90*DEG), VECTOR(0, 0, -3))
DIRECTLY;
WRITE("Grasp failed; Type a `1' to retry");
READ(flag);
IF flag ≠ 1 THEN ABORT;
MOVE YELLOW TO bracket_grasp DIRECTLY;
CENTER YELLOW
ON OPENING < .2*CM DO ABORT ("Closed on air");
END missed;
bracket_grasp α← YELLOW;
AFFIX bracket TO YELLOW;
.FILL
Finally, the whole task is made into a library routine so it can be
`called' (ie. expanded) as a subtask from a higher level task.
.NOFILL
DEFINE OZ="((72.007789*GM*CM)/(SEC*SEC))";
ROUTINE bolt_on_bracket;
whole_task: BEGIN
PLAN IF α#(YELLOW) ≠ YPARK
THEN PLAN ERROR("The yellow arm is not planned to be in its
park position, contrary to assumption in routine bolt_on_bracket");
PLAN IF FORM(AFFIXED, ANYTHING, YELLOW)
THEN PLAN ERROR("Something is affixed to the yellow hand;
the routine bolt_on_bracket expects the hand to be empty.");
.COMT 10
α{This type of compile-time check and warning to the
user is very useful for insuring that the interface
assumptions for routines are met in the planning
world just before the routine is expanded. Notice that
there is a built-in procedure, PLAN ERROR, which prints
the included message at compile-time and stops the compilation.
There is also a compile-time WRITE statement, PLAN WRITE("...").
These two different `output' statements are used so that the
user can generate WRITE statements during the compilation of
a program.α}
.END
COBEGIN
ypickup: BEGIN α{%4Pick up bracket with YELLOW%*α}
grasp(grasp_point=bracket_grasp, object=bracket,
opening_for_approach=3*CM);
MOVE bracket_hole TO beam_hole + VECTOR(0, 0, 1.3) WRT beam_hole;
MOVE YELLOW TO ⊗ + VECTOR(0, 0, .5) WRT beam_hole
ON FORCE(Z WRT beam_hole) > 50*OZ DO STOP YELLOW
ON ARRIVAL DO ABORT("I Seem to have gone too far.");
END ypickup;
bpickup: BEGIN α{%4Pick up bolt with BLUE%*α}
grasp(the_arm=BLUE, object=bolt, grasp_point=bolt,
opening_for_approach=3*CM)
END bpickup
COEND;
MOVE bolt TO beam_hole + VECTOR(0, 0, -5.3) WRT beam_hole;
normal_search(BLUE, .2*CM, 1.6*CM, 60*OZ, 9);
.COMT 8
α{Assume that the bolt is now in the hole.α}
.END
MOVE BLUE TO ⊗ * FRAME(ROT(Z,90*DEG), VECTOR(0, 0, 4))
ON FORCE(Z WRT BLUE) > 60*OZ DO STOP BLUE;
disengage: COBEGIN
foryellow: BEGIN
OPERATE YFINGERS WITH OPENING = 3*CM;
UNFIX bracket FROM YELLOW;
AFFIX bracket TO beam;
MOVE YELLOW TO YPARK
END foryellow;
forblue: BEGIN
OPERATE BFINGERS WITH OPENING = 3*CM;
UNFIX bolt FROM BLUE;
AFFIX bolt TO beam;
MOVE BLUE TO BPARK
END forblue
COEND disengage
END whole_task;
.NEWSS EXAMPLES OF COORDINATED ACTION, COORDINATED ACTION
.FILL
These two examples take into account some of the more subtle aspects
of assembly such as freeing the bracket while trying to insert the
bolt in the hole and changing the speed of the driver dynamically.
The following section of code is designed to simultaneously free the
YELLOW arm and move the BLUE arm to insert the bolt. The freeing of
the YELLOW arm is to allow the bracket to accommodate slightly along the
surface of the beam as the BLUE arm tries to insert the bolt.
.NOFILL
MOVE bolt TO beam_hole + VECTOR(0, 0, -5.3) WRT beam_hole;
.COMT 4
α{Remember that the bolt is in the BLUE hand.α}
.END
MOVE YELLOW TO ⊗
WITH FORCE = 0 ALONG X,Y OF beam_hole
ON DURATION > 0*SEC DO
insertion: BEGIN
.COMT 10
α{Notice that "DURATION > 0*SEC" is an
approximation to simultaneous motion.α}
.END
normal_search(BLUE, .2*CM, 1.6*CM, 60*OZ, 9);
.COMT 10
α{Assume that the bolt is now in the hole.α}
.END
MOVE BLUE TO ⊗ * FRAME(ROT(Z,90*DEG), VECTOR(0, 0, 4))
ON FORCE(Z WRT BLUE) > 60*OZ DO STOP YELLOW;
END insertion
ON DURATION > 4*SEC DO ABORT("Operation took too long");
.COMT 8
α{The "ON DURATION > 4*SEC DO ABORT" will generate an error
if the insertion takes more than 4 seconds. The error
will force the operator to deal with the situation at
supervisor level.α}
.END
Without the SEARCH this could be accomplished in "weak" synchrony:
MOVE bolt TO beam_hole + VECTOR(0, 0, -5.3) WRT beam_hole;
MOVE [BLUE : YELLOW]
TO [⊗ + VECTOR(0, 0, 1.6) WRT BLUE : ⊗]
WITH [ : FORCE = 0 ALONG X,Y OF beam_hole]
ON [FORCE(Z WRT BLUE) > 60*OZ : ] DO [STOP : STOP];
.FILL
It is awkward to include the SEARCH in such a scheme. In fact, this
type of coordination comes up in a number of other places. For
example, if you want to operate a device (eg. the DRIVER) and move an
arm or camera "at the same time." Events and synchronizing primitives
have been added to solve these control problems. Consider the
following way of programming this task:
.NOFILL
EVENT y_ready, b_ready;
.COMT 4
α{y_ready is an event signalling that the YELLOW
arm is ready to move. b_ready indicates that the
BLUE arm is ready to move.α}
.END
MOVE bolt TO beam_hole + VECTOR(0, 0, -5.3) WRT beam_hole;
bolt_insert: COBEGIN
free_yellow: BEGIN
SIGNAL y_ready;
WAIT b_ready;
MOVE YELLOW TO ⊗
WITH FORCE = 0 ALONG X,Y OF beam_hole
ON DURATION > 4*SEC DO ABORT("Took too long");
END free_yellow
blue_insert: BEGIN α{%4Use blue to insert bolt%*α}
SIGNAL b_ready;
WAIT y_ready;
normal_search(BLUE, .2*CM, 1.6*CM, 60*OZ, 9);
.COMT 8
α{Assume that the bolt is now in the hole.α}
.END
MOVE BLUE TO ⊗ * FRAME(ROT(Z,90*DEG), VECTOR(0, 0, 4))
ON FORCE(Z WRT BLUE) > 60*OZ DO STOP YELLOW;
END blue_insert;
COEND bolt_insert;
.FILL
Consider the problem of inserting in a screw and checking to make sure
that it does not bind. If, after a short time, the screw does not
bind, the speed of the DRIVER can be increased. However, if it DOES
bind, everything should stop and the DRIVER should be reversed to try
to unbind the screw.
.NOFILL
EVENT d_ready, b_ready;
SCALAR sp, flag;
sp α← 30;
flag α← 1;
WHILE flag DO
screw_loop: BEGIN
move_screw: COBEGIN α{%4Move and screw simultaneously%*α}
drive: BEGIN
SIGNAL d_ready;
WAIT b_ready;
OPERATE DRIVER
WITH VELOCITY = sp
ON DURATION > 8*SEC DO ABORT("Took too long");
END drive
downward_force: BEGIN
SIGNAL b_ready;
WAIT d_ready;
MOVE BLUE TO ⊗
WITH FORCE = 0 ALONG Z OF BLUE
WITH FORCE = 40*OZ ALONG Z OF BLUE
bind: ON TORQUE(Z WRT BLUE) > 80*OZ DO
bound: BEGIN
DISABLE catch_ok;
STOP BLUE;
STOP DRIVER;
COBEGIN α{%4Try to unbind by reversing the driver%*α}
unscrew: BEGIN
SIGNAL d_ready;
WAIT b_ready;
sp α← -60;
OPERATE DRIVER
WITH VELOCITY = SP
ON DURATION > 4*SEC DO ABORT("Can't unbind");
END unscrew
upward_force BEGIN
SIGNAL b_ready;
WAIT d_ready;
MOVE BLUE TO ⊗
WITH FORCE = 0 ALONG Y, X OF BLUE
WITH FORCE = 40*OZ ALONG Z OF BLUE
out_ok: ON FORCE(Z WRT BLUE)<20*OZ DO
BEGIN
STOP DRIVER;
STOP BLUE;
.COMT 22
α{Leave flag true for retry.α}
.END
END
too_much_time: ON DURATION>4*SEC DO ABORT;
END upward_force
COEND
END bound
catch_ok: ON DURATION > 1*SEC DO
BEGIN
DISABLE bind;
ENABLE torqued_in_ok;
sp α← 60; α{maybe this should be CRITICAL.α}
END
torqued_in_ok: DEFER ON TORQUE(Z WRT BLUE) > 80*OZ DO
BEGIN
STOP DRIVER;
STOP BLUE;
flag α← 0; α{indicating no retryα}
END;
END downward_force
COEND move_screw
END screw_loop;
.NEWSS A α`VERY HIGH LEVELα' EXAMPLE
.FILL
This very short example demonstrates the use of assembly-oriented
special primitives to simplify a task specification, as well as
some of the object description conventions used by those primitives.
Here, the task is the same as that of {sssref ex1}. For a fuller
explanation of the use of such primitives and another, longer
example, see {secref vhl}.
.NOFILL
FRAME beam, bracket, bolt;
FRAME bracket_bore, beam_bore;
FRAME bolt_grasp, bracket_handle;
.comt 0
α{We must first describe the various components. We expect that
eventually the process of making such descriptions will become
very largely automated, as computer programs begin to play an
increasingly active role in mechanical design. See {ssref obd}.α}
.end
ASSERT FORM(TYPE, beam, object);
ASSERT FORM(GEOMED, beam, "beam.B3D[AL,HE]"); α{%4Shape description%*α}
ASSERT FORM(SUBPART, beam, beam_bore);
ATTACH beam_bore TO beam RIGIDLY AT TRANS(ROT(Y,90),VECTOR(0,1.5,6));
ASSERT FORM(TYPE, bracket, object);
ASSERT FORM(GEOMED, bracket, "BRACK.B3D[AL,HE]"); α{%4Shape description.%*α}
ASSERT FORM(SUBPART, bracket, bracket_bore);
ASSERT FORM(SUBPART, bracket, bracket_handle);
ATTACH bracket_bore TO bracket RIGIDLY AT TRANS(ROT(X,180),VECTOR(5.1,2,0));
ATTACH bracket_handle TO bracket RIGIDLY AT TRANS(ROT(X,180),NILVEC);
ASSERT FORM(TYPE, bolt, SHAFT);
ASSERT FORM(DIAMETER, bolt, 0.5*CM);
ASSERT FORM(TOP_END, bolt, head_type1);
ASSERT FORM(BOTTOM_END, bolt, tiptype1);
ASSERT FORM(TYPE, tiptype1, FLAT_END);
ASSERT FORM(TYPE, bracket_bore, BORE);
ASSERT FORM(DIAMETER, bracket_bore, 0.502*CM);
ASSERT FORM(LENGTH, bracket_bore, 0.5*CM);
ASSERT FORM(TOP_END, bracket_bore, bracket_hole1);
ASSERT FORM(BOTTOM_END, bracket_bore, bracket_hole1);
.comt 4
α{Et ceteraα}
.end
.comt 0
α{Also, describe how things go together:α}
.end
ASSERT FORM(TYPE, beam_assembly, ASSEMBLY);
ASSERT FORM(SUBPART, beam_assembly, beam);
ASSERT FORM(SUBPART, beam_assembly, bolt);
ASSERT FORM(SUBPART, beam_assembly, bracket);
ASSERT FORM(bracket, FITS_ONTO, beam_assembly, AT,
TRANS(ROT(Y,90),VECTOR(5.1,2,0));
ASSERT FORM(bolt, FITS_ONTO, beam_assembly, AT,
TRANS(ROT(Y,90),VECTOR(5.1,2.3,0));
ASSERT FORM(MATED, beam_hsurf, bracket_bottom);
ASSERT FORM(ALIGNED, beam_bore, bracket_bore);
ASSERT FORM(RUNS_THRU, bolt, bracket_bore);
ASSERT FORM(RUNS_THRU, bolt, beam_bore);
.COMT 4
α{Et cetera.α}
.END
.comt 0
α{Now, describe the initial scene. Here, assume that the initial object
locations are known precisely.α}
.end
bracket α← FRAME(NILROT,VECTOR(20,40,0));
beam α← FRAME(NILROT,VECTOR(10,60,0));
bolt α← FRAME(ROT(Y,180),VECTOR(30,50,5));
grasp bracket AT TRANS(ROT(Y,180),2*Z) WITH YELLOW;
.comt 0
α{The system will use its internal model of the bracket to
fill in the expected hand opening.α}
.end
FIT bracket ONTO beam_assembly
USING YELLOW
AFTERWARDS HOLD bracket WITH YELLOW;
.comt 0
α{The system will use the object description information to fill
in the exact location to which to move the bracket. Also, it
will pick appropriate techniques to ensure that the bracket
is appropriately aligned. The AFTERWARDS clause tells the
system that it is to use the yellow arm to hold the bracket in placeα}
.end
INSERT bolt INTO bracket_hole1 USING BLUE;
.comt 0
α{Once again, the system will fill in the details, such as how
the bolt is to be grasped, how it should be brought
to the hole, how it will be pushed in, and so forth.α}
.end
RELEASE bracket; α{%4Since the bolt now holds it on.%*α}
.FILL